package shared;

import client.ClientController;
import server.ProfessionFactory.profession_type;
import java.util.List;
import packet.Command;

/**
 * A player portfolio<br/>
 * Holds financial data for a player
 * @author Joel Garboden
 */
public class PlayerPortfolio extends Command
{
  public String name;
  public String profession;

  public profession_type prof_ID;

  public int salary;

  public int monthlyTaxes;
  public double taxInterestRate;

  public int monthlyHousePayment;
  public double houseInterestRate;
  public int remainingHousePayment;

  public int monthlySchoolPayment;
  public int remainingSchoolPayment;

  public int monthlyCarPayment;
  public double carInterestRate;
  public int remainingCarPayment;

  public int monthlyCardPayment;
  public double cardInterestRate;
  private int remainingCardPayment;

  public int weeklyRetailPayment;
  public int weeklyMiscPayment;

  public int weeklyCostPerChild;
  public int childCount;
  public int remainingChildExpense;

  public int monthlyLivingExpensePayment;
  public int remainingMonthlyExpensePayment;

  public int remainingLoanAmount;
  public double monthlyLoanInterestRate;

  private int cash;

  public int weekCounter;

  public int payWeek;
  
  //TODO ArrayList of Dividends
  //TODO ArrayList of Real Estate  
  //TODO ArrayList of Businesses  

  public int remainingWeeklyPayment; //derived

  public int remainingMonthlyPayment; //derived

  public float PercentOutOfRatRace; //derived

  public int p_income_needed; //derived

  //Current job performance rating
  public int performancePoints;
  //Next step up
  public int performanceThreshold;
  
  public List<Integer> performanceSteps;
  public int insuranceDeductible;
  public int weekSuspension;

  public PlayerPortfolio()
  {
    this.priority = Consts.Priorities.DATA_UPDATE;
    name = "Uninitialized";
  }

  /**
   * @param name player name
   */
  public PlayerPortfolio(String name)
  {
    this.priority = Consts.Priorities.DATA_UPDATE;
    this.name = name;
  }

  /**
   * @param name portfolio name
   */
  public void setName(String name)
  {
    this.name = name;
  }

  /**
   * @return portfolio name
   */
  public String getName()
  {
    return name;
  }
  
  public int getInsuranceDeductible()
  {
    return insuranceDeductible;
  }
  
  public int getWeek()
  {
    return weekCounter;
  }

  /**
   * Mutator for bank balance changes, no scaling.
   * @param balanceChange value to increase cash by
   * @throws IllegalArgumentException
   */
  public void balanceChange(int flat)
  {
    cash += flat;
  }
  
  public int getMonthlyAssetIncome()
  {
    //Interest + dividends + real estate + businesses
    return 0;
  }
  
  public int getTotalIncome()
  {
    return this.salary + getMonthlyAssetIncome();
  }
  
  public int getPayCheckAmount()
  {
    //Was monthly cash flow
    return getTotalIncome() - getTotalExpenses();
  }
  
  public int getTotalExpenses()
  {
    //taxes + hmortgage + schoo loan payment + car payment + credit card payment + retail payment + other expenses + child expenses + bank loan payment
    return 0;
  }

  /**
   * When player begins their turn, specific events will happen.  E.g. waking up in real life
   */
  public void nextWeek()
  {
    ++weekCounter;
    if(weekSuspension > 0)
    {
      --weekSuspension;
    }
    else if(weekCounter % payWeek == 0)
    {
      cash += getPayCheckAmount();
    }
  }

  /**
   * Pays bills and calculates remaining expenses
   */
  public void payBills()
  {
    weeklyBills();

    if(weekCounter % Consts.MONTHLY_BILL_DAYS == 0)
    {
      monthlyBills();
    }
  }

  /**
   * Handles bill payments and interest on weekly expenses
   */
  private void weeklyBills()
  {
    if(cash - weeklyMiscPayment >= 0)
    {
      cash -= weeklyMiscPayment;
      remainingWeeklyPayment -= weeklyMiscPayment;
    }
    else
    {
      remainingWeeklyPayment += weeklyMiscPayment;
    }

    if(cash - weeklyRetailPayment >= 0)
    {
      cash -= weeklyRetailPayment;
      remainingWeeklyPayment -= weeklyRetailPayment;
    }
    else
    {
      remainingWeeklyPayment += weeklyRetailPayment;
    }

    if(cash - remainingChildExpense >= 0)
    {
      cash -= remainingChildExpense;
      remainingChildExpense -= childCount * weeklyCostPerChild;
    }
    else
    {
      remainingChildExpense += childCount * weeklyCostPerChild;
    }
  }

  /**
   * Handles bill payments and interest on monthly expenses
   */
  private void monthlyBills()
  {
    if(cash - monthlyTaxes >= 0)
    {
      cash -= monthlyTaxes;
    }
    else
    {
      monthlyTaxes += monthlyTaxes *taxInterestRate;
    }

    //no automatic payment of loan
    remainingLoanAmount += remainingLoanAmount * monthlyLoanInterestRate;

    if(cash - monthlyLivingExpensePayment >= 0)
    {
      cash -= monthlyLivingExpensePayment;
      remainingMonthlyExpensePayment -= monthlyLivingExpensePayment;
    }
    else
    {
      remainingMonthlyExpensePayment += monthlyLivingExpensePayment;
    }

    if(cash - monthlyHousePayment >= 0)
    {
      cash -= monthlyHousePayment;
      remainingHousePayment -= monthlyHousePayment;
    }
    else
    {
      remainingHousePayment += monthlyHousePayment + (remainingHousePayment * houseInterestRate);
    }

    if(cash - monthlySchoolPayment >= 0)
    {
      cash -= monthlySchoolPayment;
      remainingSchoolPayment -= monthlySchoolPayment;
    }
    else
    {
      remainingSchoolPayment += monthlySchoolPayment;
    }

    if(cash - monthlyCarPayment >= 0)
    {
      cash -= monthlyCarPayment;
      remainingCarPayment -= monthlyCarPayment;
    }
    else
    {
      remainingCarPayment += monthlyCarPayment;
    }

    if(cash - monthlyCardPayment >= 0)
    {
      cash -= monthlyCardPayment;
      remainingCardPayment -= monthlyCardPayment;
    }
    else
    {
      remainingCardPayment += monthlyCardPayment;
    }

    remainingMonthlyPayment += remainingHousePayment + remainingSchoolPayment
                               + remainingCarPayment + remainingCardPayment
                               + remainingLoanAmount;
  }


  @Override
  public String toString()
  {
    return name + " - " + profession + " $" + cash;
  }

  /**
   *
   */
  void isPromoted()
  {
    //Use performancepoints, performancethreshold, and performanceSteps
    throw new UnsupportedOperationException("Not yet implemented");
  }


  /**
   *
   * @param incomeChangeFlat
   * @param incomeChangeFloat
   */
  public void incomeChange(int flat, double scalar)
  {
    if(0 == flat && 0 == scalar)
    {
      System.out.println("No payment increase");
    }
    else if(flat != 0)
    {
      salary += flat;
    }
    else if(scalar != 0)
    {
      salary *= scalar;
    }
  }

  /**
   * Accessor
   * @return cash
   */
  public int cashOnHand()
  {
    return cash;
  }

  /**
   * Accessor
   * @return salary
   */
  public int salary()
  {
    return salary;
  }

  /**
   *
   * @param rateChangeFlat
   * @param rateChangeScalar
   */
  public void cardInterestRateChange(int rateChangeFlat, double rateChangeScalar)
  {
    System.err.println("Not yet implemented");
  }

  /**
   * Finds scaled money
   * @param moneyMagnitude
   */
  public void findMoney(int moneyMagnitude)
  {//TODO create calculation for scaled monetary gain
    //moneyMagnitude
    //cash
    //salary
    //weekCounter

    int modifier = moneyMagnitude + weekCounter;
    cash += salary / modifier;

  }


  /**
   *
   * @param 
   */
  public void jobPerformanceChange(int flat, double scalar)
  {
    this.performancePoints += performancePoints;
    if(performancePoints >= performanceThreshold)
    {
      //promote player
    }
    else
    {
      //do nothing
    }
  }

  public void insuranceDeductibleChange(int flat, double scalar)
  {
    if(0 == flat && 0 == scalar)
    {
      System.out.println("No deductible increase.");
    }
    else if(flat != 0)
    {
      insuranceDeductible += flat;
    }
    else if(scalar != 0)
    {
      insuranceDeductible *= scalar;
    }
  }

  public void chargeChange(int flat, double scalar)
  {
    if(0 == flat && 0 == scalar)
    {
      System.out.println("No charge.");
    }
    else if(flat != 0)
    {
      remainingCardPayment += flat;
    }
    else if(scalar != 0)
    {
      remainingCardPayment *= scalar;
    }    
  }

  public void printAll()
  {
    System.out.println("Name:" + name);
    System.out.println("Profession:" + profession);

//    System.out.println("Profession ID:" + prof_ID);

//    System.out.println("Salary: " + salary);

//    System.out.println("Monthyl taxes: " + monthlyTaxes);
//    System.out.println("Tax interest rate: " + taxInterestRate);
//
//    System.out.println("Monthly house payments: " + monthlyHousePayment);
//    System.out.println("House interest rate: " + houseInterestRate);
//    System.out.println("Remaining house payment: " + remainingHousePayment);
//
//    System.out.println("Monthly school payment: " + monthlySchoolPayment);
//    System.out.println("Remaining school payment: " + remainingSchoolPayment);
//
//    System.out.println("Monthly car payment: " + monthlyCarPayment);
//    System.out.println("Car interest rate: " + carInterestRate);
//    System.out.println("Remaining car payment: " + remainingCarPayment);
//
//    System.out.println("Monthly card payment: " + monthlyCardPayment);
//    System.out.println("Card interest rate: " + cardInterestRate);
//    System.out.println("Reminaing card payment: " + remainingCardPayment);
//
//    System.out.println("Weekly retail payment: " + weeklyRetailPayment);
//    System.out.println("Weekly misc payment: " + weeklyMiscPayment);
//
//    System.out.println("Weekly cost per child: " + weeklyCostPerChild);
//    System.out.println("Child count: " + childCount);
//    System.out.println("Remaining child expense: " + remainingChildExpense);
//
//    System.out.println("Monthly living expense payment: " + monthlyLivingExpensePayment);
//    System.out.println("Remaining monthy living expenses: " + remainingMonthlyExpensePayment);
//
//    System.out.println("Mothly asset income: " + getMonthlyAssetIncome()); //was passive income
//
//    System.out.println("Remaining loan amount: " + remainingLoanAmount);
//    System.out.println("Monthly loan interest rate: " + monthlyLoanInterestRate);

//    System.out.println("Paycheck amount: " + paycheckAmount); //derived: Paycheck amount = (salary + assets) - total expenses?

    System.out.println("Cash: " + cash);

    System.out.println("Week counter: " + weekCounter);
//
//    System.out.println("Pay week: " + payWeek);
//
//    System.out.println("Remaining weekly payment: " + remainingWeeklyPayment); //derived
//
//    System.out.println("Remaining monthly payment: " + remainingMonthlyPayment); //derived
//
//    System.out.println("Percent out of rat race: " + PercentOutOfRatRace); //derived
//
//    System.out.println("Total income: " + getTotalIncome()); //derived
//    System.out.println("Total expenses: " + totalExpenses); //derived
//    System.out.println("Income needed: " + p_income_needed); //derived
//
//    //Current job performance rating
//    System.out.println("Performance points: " + performancePoints);
//    //Next step up
//    System.out.println("Performance threshold: " + performanceThreshold);
//
//    //public List<Integer> performanceSteps);
//    System.out.println("Insurance deductible: " + insuranceDeductible);
//    System.out.println("Week suspension: " + weekSuspension);
  }

  @Override
  public boolean execCommand(ClientController client)
  {
    client.updatePortfolio(this);
    return true;
  }
}
